package com.lxg.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lxg.security.filter.LoginKaptchaFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 陆小根
 * date: 2022/04/25
 * Description:
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  // 自定义内存数据源
  @Bean
  public UserDetailsService userDetailsService() {
    InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
    inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("admin").build());
    return inMemoryUserDetailsManager;
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService());
  }

  @Override
  @Bean // 本地的需要暴露给工厂
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Bean
  public LoginKaptchaFilter loginKaptchaFilter() throws Exception {
    LoginKaptchaFilter loginKaptchaFilter = new LoginKaptchaFilter();
    // 1.认证url
    loginKaptchaFilter.setFilterProcessesUrl("/doLogin");
    // 2.认证 接收参数
    loginKaptchaFilter.setUsernameParameter("uname");
    loginKaptchaFilter.setPasswordParameter("passwd");
    loginKaptchaFilter.setKaptchaParameter("kaptcha");
    // 3.指定认证管理器
    loginKaptchaFilter.setAuthenticationManager(authenticationManagerBean());
    // 4.指定成功时的处理
    loginKaptchaFilter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
      @Override
      public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "登录成功");
        result.put("用户信息", authentication.getPrincipal());
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpStatus.OK.value());
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
      }
    });
    // 5.指定失败时的处理
    loginKaptchaFilter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "登录失败: " + exception.getMessage());
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        response.setContentType("application/json;charset=UTF-8");
        String s = new ObjectMapper().writeValueAsString(result);
        response.getWriter().println(s);
      }
    });
    return loginKaptchaFilter;
  }


  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .mvcMatchers("/vc.jpg").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(new AuthenticationEntryPoint() {
              @Override
              public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                response.setContentType("application/json;charset=UTF-8");
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.getWriter().println("必须认证之后才能访问!");
              }
            })
            .and()
            .logout()
            .and()
            .csrf().disable()
    ;

    http.addFilterAt(loginKaptchaFilter(), UsernamePasswordAuthenticationFilter.class);
  }
}
